package com.ruoyi.web.controller.prt;

import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.*;
import com.ruoyi.common.utils.http.HttpUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.prt.domain.PayInfo;
import com.ruoyi.prt.domain.PrtEpLog;
import com.ruoyi.prt.domain.PrtRechargeLog;
import com.ruoyi.prt.domain.PrtRechargePrice;
import com.ruoyi.prt.domain.vo.PrtRechargeLogVO;
import com.ruoyi.prt.service.IPrtEpLogService;
import com.ruoyi.prt.service.IPrtRechargeLogService;
import com.ruoyi.prt.service.IPrtRechargePriceService;
import com.ruoyi.system.service.ISysUserService;
import lombok.SneakyThrows;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.repository.query.Param;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import static com.ruoyi.common.constant.Constants.*;

/**
 * 充值记录Controller
 *
 * @author xiaobo Yan
 * @date 2021-03-31
 */
@RestController
@RequestMapping("/prt/rechargelog")
public class PrtRechargeLogController extends BaseController
{
    @Autowired
    private IPrtRechargeLogService prtRechargeLogService;

    @Autowired
    private ISysUserService sysUserService;

    @Autowired
    private IPrtRechargePriceService iPrtRechargePriceService;

    @Autowired
    private IPrtEpLogService iPrtEpLogService;

    /**
     * 查询充值记录列表
     */
    @PreAuthorize("@ss.hasPermi('system:rechargelog:list')")
    @GetMapping("/list")
    public TableDataInfo list(PrtRechargeLog prtRechargeLog)
    {
        startPage();
        List<PrtRechargeLog> list = prtRechargeLogService.selectPrtRechargeLogList(prtRechargeLog);
        return getDataTable(list);
    }

    /**
     * 导出充值记录列表
     */
    @PreAuthorize("@ss.hasPermi('system:rechargelog:export')")
    @Log(title = "充值记录", businessType = BusinessType.EXPORT)
    @GetMapping("/export")
    public AjaxResult export(PrtRechargeLog prtRechargeLog)
    {
        List<PrtRechargeLog> list = prtRechargeLogService.selectPrtRechargeLogList(prtRechargeLog);
        ExcelUtil<PrtRechargeLog> util = new ExcelUtil<PrtRechargeLog>(PrtRechargeLog.class);
        return util.exportExcel(list, "rechargelog");
    }

    /**
     * 获取充值记录详细信息
     */
    @PreAuthorize("@ss.hasPermi('system:rechargelog:query')")
    @GetMapping(value = "/{rechargeLogId}")
    public AjaxResult getInfo(@PathVariable("rechargeLogId") String rechargeLogId)
    {
        return AjaxResult.success(prtRechargeLogService.selectPrtRechargeLogById(rechargeLogId));
    }

    /**
     * 新增充值记录
     */
    @PreAuthorize("@ss.hasPermi('system:rechargelog:add')")
    @Log(title = "充值记录", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@RequestBody PrtRechargeLog prtRechargeLog)
    {
        return toAjax(prtRechargeLogService.insertPrtRechargeLog(prtRechargeLog));
    }

    /**
     * 修改充值记录
     */
    @PreAuthorize("@ss.hasPermi('system:rechargelog:edit')")
    @Log(title = "充值记录", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@RequestBody PrtRechargeLog prtRechargeLog)
    {
        return toAjax(prtRechargeLogService.updatePrtRechargeLog(prtRechargeLog));
    }

    /**
     * 删除充值记录
     */
    @PreAuthorize("@ss.hasPermi('system:rechargelog:remove')")
    @Log(title = "充值记录", businessType = BusinessType.DELETE)
	@DeleteMapping("/{rechargeLogIds}")
    public AjaxResult remove(@PathVariable String[] rechargeLogIds)
    {
        return toAjax(prtRechargeLogService.deletePrtRechargeLogByIds(rechargeLogIds));
    }

    /**
     * 获取打印记录详细信息
     */
    @GetMapping("/getRechargeLog")
    @Log(title = "获取打印记录详细信息", businessType = BusinessType.SELECT)
    @PreAuthorize("@ss.hasRole('mobile')")
    public AjaxResult getRechargeLog(PrtRechargeLogVO prtRechargeLog)
    {
        prtRechargeLog.setUser(SecurityUtils.getUserId());
        return AjaxResult.success(prtRechargeLogService.selectPrtRechargeLogList(prtRechargeLog));
    }

    @SneakyThrows
    @GetMapping("/prePay")
    @Log(title = "微信客户支付请求", businessType = BusinessType.SELECT)
    @PreAuthorize("@ss.hasRole('mobile')")
    public AjaxResult prePay(String id) {
        AjaxResult ajaxResult = new AjaxResult();
        if (id == null || id.isEmpty())
            return AjaxResult.error("id is empty");
        PrtRechargePrice prtRechargePrice = iPrtRechargePriceService.selectPrtRechargePriceById(id);
        Double price = prtRechargePrice.getRechargePrice().doubleValue() * 100;

        LoginUser user =  SecurityUtils.getLoginUser();
        String randomNonceStr = RandomUtils.generateMixString(32);
        String orderId = CommonUtil.getRandomOrderId();
        String prepayId = unifiedOrder(user.getUser().getOpenid(), user.getIpaddr(), randomNonceStr, orderId, price.intValue());
        if(StringUtils.isBlank(prepayId)) {
            prepayId = "-1";
            return AjaxResult.error(prepayId);
        }
        Date date = new Date();
        PrtRechargeLog prtRechargeLog = new PrtRechargeLog();
        prtRechargeLog.setRechargeLogId(com.ruoyi.common.utils.StringUtils.getUUID());
        BigDecimal bigDecimal = prtRechargePrice.getRechargePrice().add(prtRechargePrice.getRechargeConpon());
        prtRechargeLog.setRechargePrice(bigDecimal);
        prtRechargeLog.setPayPrice(prtRechargePrice.getRechargePrice());
        prtRechargeLog.setCouponPrice(prtRechargePrice.getRechargeConpon());
        prtRechargeLog.setOrderId(orderId);
        prtRechargeLog.setPayChannel("weixin");
        prtRechargeLog.setPayStatus("0");
        prtRechargeLog.setUser(user.getUserId());
        prtRechargeLog.setUserName(user.getUsername());
        prtRechargeLog.setCreatedTime(date);
        prtRechargeLog.setCreatedName(randomNonceStr);
        int dbRes = prtRechargeLogService.insertPrtRechargeLog(prtRechargeLog);

        String timeStamp = (date.getTime()/1000) + "";
        String payData = "appId=" + BX_ID + "&nonceStr=" + randomNonceStr + "&package=prepay_id=" + prepayId +
                "&signType=MD5&timeStamp=" + timeStamp + "&key=" + PAY_KEY;
        System.out.print("payData: " + payData + "\r\n");
        String paySign = CommonUtil.getMD5(payData).toUpperCase();

        ajaxResult.put("signType", "MD5");
        ajaxResult.put("rechargeLogId", prtRechargeLog.getRechargeLogId());
        ajaxResult.put("dbRes", dbRes);
        ajaxResult.put("nonceStr", randomNonceStr);
        ajaxResult.put("paySign", paySign);
        ajaxResult.put("timeStamp", timeStamp);
        ajaxResult.put("package", "prepay_id=" + prepayId);
        return AjaxResult.success(ajaxResult);
    }

    @GetMapping(value = "/notify")
    @Log(title = "提交充值订单", businessType = BusinessType.OTHER)
    @PreAuthorize("@ss.hasRole('mobile')")
    public AjaxResult notify(String rechargeLogId){
        SysUser user = SecurityUtils.getLoginUser().getUser();
        PrtRechargeLog prtRechargeLog = prtRechargeLogService.selectPrtRechargeLogById(rechargeLogId);
        if ((prtRechargeLog != null) && (prtRechargeLog.getUser().equals(user.getUserId()))){
            prtRechargeLog.setPayStatus("1");
            prtRechargeLogService.updatePrtRechargeLog(prtRechargeLog);

            //修改用户余额
            BigDecimal bigDecimal = user.getBalance();
            bigDecimal = bigDecimal.add(prtRechargeLog.getRechargePrice());
            user.setBalance(bigDecimal);
            System.out.println("bigDecimal:" + bigDecimal);
            SecurityUtils.getLoginUser().setUser(user);

            //创建一条订单记录
            PrtEpLog prtEpLog = new PrtEpLog();
            prtEpLog.setEpLogId(com.ruoyi.common.utils.StringUtils.getUUID());
            prtEpLog.setUser(user.getUserId());
            prtEpLog.setUserName(user.getUserName());
            prtEpLog.setUserTime(prtRechargeLog.getCreatedTime());
            prtEpLog.setFundType("充值");
            prtEpLog.setFundDirection(0);
            prtEpLog.setPrice(prtRechargeLog.getRechargePrice());
            iPrtEpLogService.insertPrtEpLog(prtEpLog);
            return AjaxResult.success(sysUserService.updateBalance(user.getUserId(), bigDecimal));
        }else {
            return AjaxResult.error("没有预充值记录");
        }
    }

    /**
     * 调用统一下单接口
     * @param openId
     */
    private String unifiedOrder(String openId, String clientIP, String randomNonceStr, String orderId, int total) {
        try {
            String url = URL_UNIFIED_ORDER;
            PayInfo payInfo = createPayInfo(openId, clientIP, randomNonceStr, orderId, total);
            String md5 = getSign(payInfo);
            payInfo.setSign(md5);

            System.out.println("+++md5 value: " + md5);
            String xml = CommonUtil.payInfoToXML(payInfo);
            xml = xml.replace("__", "_").replace("<![CDATA[1]]>", "1");
            System.out.println(xml);

            String buffer = HttpUtils.sendPost(url, xml);
            System.out.println("unifiedOrder request return body: \n" + buffer);
            Map<String, String> result = CommonUtil.parseXml(buffer);

            String return_code = result.get("return_code");
            if(StringUtils.isNotBlank(return_code) && return_code.equals("SUCCESS")) {
                String return_msg = result.get("return_msg");
                if(StringUtils.isNotBlank(return_msg) && !return_msg.equals("OK")) {
                    System.out.println("unifiedOrder error");
                    return null;
                }
                String prepay_Id = result.get("prepay_id");
                return prepay_Id;
            } else {
                return null;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private PayInfo createPayInfo(String openId, String clientIP, String randomNonceStr, String orderId, int total) {
        Date date = new Date();
        String timeStart = TimeUtils.getFormatTime(date, TIME_FORMAT);
        String timeExpire = TimeUtils.getFormatTime(TimeUtils.addDay(date, TIME_EXPIRE), TIME_FORMAT);

        PayInfo payInfo = new PayInfo();
        payInfo.setAppid(BX_ID);
        payInfo.setMch_id(MCH_ID);
        payInfo.setDevice_info("WEB");
        payInfo.setNonce_str(randomNonceStr);
        payInfo.setSign_type("MD5");//默认即为MD5
        payInfo.setBody("word");
        payInfo.setAttach("print");
        payInfo.setOut_trade_no(orderId);
        payInfo.setTotal_fee(total);
        payInfo.setSpbill_create_ip(clientIP);
        payInfo.setTime_start(timeStart);
        payInfo.setTime_expire(timeExpire);
        payInfo.setNotify_url(URL_NOTIFY);
        payInfo.setTrade_type("JSAPI");
        payInfo.setLimit_pay("no_credit");
        payInfo.setOpenid(openId);
        return payInfo;
    }

    private String getSign(PayInfo payInfo) throws Exception {
        StringBuffer sb = new StringBuffer();
        sb.append("appid=" + payInfo.getAppid())
                .append("&attach=" + payInfo.getAttach())
                .append("&body=" + payInfo.getBody())
                .append("&device_info=" + payInfo.getDevice_info())
                .append("&limit_pay=" + payInfo.getLimit_pay())
                .append("&mch_id=" + payInfo.getMch_id())
                .append("&nonce_str=" + payInfo.getNonce_str())
                .append("&notify_url=" + payInfo.getNotify_url())
                .append("&openid=" + payInfo.getOpenid())
                .append("&out_trade_no=" + payInfo.getOut_trade_no())
                .append("&sign_type=" + payInfo.getSign_type())
                .append("&spbill_create_ip=" + payInfo.getSpbill_create_ip())
                .append("&time_expire=" + payInfo.getTime_expire())
                .append("&time_start=" + payInfo.getTime_start())
                .append("&total_fee=" + payInfo.getTotal_fee())
                .append("&trade_type=" + payInfo.getTrade_type())
                .append("&key=" + PAY_KEY);
        System.out.println("排序后的拼接参数：" + sb.toString());
        return CommonUtil.getMD5(sb.toString().trim()).toUpperCase();
    }
}
